package com.tangguangdi.shield.server.permission;

import com.tangguangdi.base.common.entity.register.ApiDefinition;
import com.tangguangdi.base.common.entity.register.AppDefinition;
import com.tangguangdi.base.common.entity.register.UserDefinition;
import com.tangguangdi.base.common.enums.register.PermissionRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;


@Service
public class PermissionServer {

    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Resource
    private PermissionCache cache;

    public final PermissionResult check(String appName, String url, String method, String token) {
        PermissionResult result = new PermissionResult();
        String accessUrl = getAccessUrl(appName, url, method);
        if (accessUrl != null) {
            ApiDefinition resource = cache.getApis(appName).getIfPresent(accessUrl);
            switch (PermissionRule.matchCode(resource.getRule())) {
                case None:
                    result = noneHandler(url, method, token, resource, checkUser(token));
                    break;
                case Login:
                    result = loginHandler(url, method, token, resource, checkUser(token));
                    break;
                case Url:
                    result = urlHandler(url, method, token, resource, checkUser(token));
                    break;
            }
        }
        return result;
    }

    private PermissionResult noneHandler(String url, String method, String token, ApiDefinition resource, UserDefinition user) {
        if (user != null) {
            return successResult(user);
        }
        return successResult(null);
    }

    private PermissionResult loginHandler(String url, String method, String token, ApiDefinition resource, UserDefinition user) {
        if (user != null) {
            return successResult(user);
        }
        return new PermissionResult().setCode(HttpStatus.UNAUTHORIZED);
    }

    private PermissionResult urlHandler(String url, String method, String token, ApiDefinition resource, UserDefinition user) {
        if (user != null) {
            for (String userUrl : user.getUrls()) {
                if (antPathMatcher.match(userUrl, url + ":" + method)) {
                    return successResult(user);
                }
            }
            return new PermissionResult().setCode(HttpStatus.FORBIDDEN);
        }
        return new PermissionResult().setCode(HttpStatus.UNAUTHORIZED);
    }

    private PermissionResult successResult(UserDefinition user) {
        PermissionResult result = new PermissionResult();
        result.setSuccess(true);
        result.setUser(user);
        result.setCode(HttpStatus.OK);
        return result;
    }

    private String getAccessUrl(String appName, String url, String method) {
        List<String> accessUrls = new ArrayList<>();
        String finalUrl = getUrl(appName, url, method);
        for (String api : cache.getApis(appName).asMap().keySet()) {
            if (antPathMatcher.match(api, finalUrl)) {
                accessUrls.add(api);
            }
        }
        if (accessUrls.size() > 0) {
            if (accessUrls.size() > 1) {
                for (String accessUrl : accessUrls) {
                    if (finalUrl.equals(accessUrl)) {
                        return accessUrl;
                    }
                }
            }
            return accessUrls.get(0);
        }
        return null;
    }

    private String getUrl(String appName, String url, String method) {
        StringBuilder builder = new StringBuilder();
        AppDefinition app = cache.getApps().getIfPresent(appName);
        String newUrl = url.replace(app.getPrefix(), "");
        builder.append(newUrl);
        builder.append(":");
        builder.append(method);
        return builder.toString();
    }

    private UserDefinition checkUser(String token) {
        if (token != null && !"".equals(token)) {
            UserDefinition user = cache.getUser(token);
            if (user != null) {
                return user;
            }
        }
        return null;
    }

}
